package com.viroyal.monitorlib.network.socket;

import com.google.gson.Gson;
import com.hwangjr.rxbus.RxBus;
import com.suntiago.baseui.utils.log.Slog;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

/**
 * Created by cxy on 2016/9/18.
 */
@ChannelHandler.Sharable
public class ClientHandler extends ChannelInboundHandlerAdapter {
    private static final String TAG = ClientHandler.class.getSimpleName();

    //ping超时计数
    private int mReadIdleCount = 0;

    private ClientSocket mSocket;

    private Gson mGson;

    public ClientHandler(ClientSocket socket) {
        mSocket = socket;
        mGson = new Gson();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Slog.e(TAG, "channelActive");
        super.channelActive(ctx);
        sendPingMessage(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Slog.e(TAG, "channelInactive");
        super.channelInactive(ctx);

        mSocket.closeAndRetry();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //重置idle计数器
        mReadIdleCount = 0;

        ByteBuf m = (ByteBuf) msg;
        try {
            CloudMessage rsp = new CloudMessage(m);
            Slog.d(TAG, "channelRead data is:" + rsp);
            if (rsp.msgType == CloudMessage.TYPE_DATA) {
                IotMessage iotMessage = mGson.fromJson(rsp.payload, IotMessage.class);
                RxBus.get().post(iotMessage);
            } else if (rsp.msgType == CloudMessage.TYPE_PING) {
                ; // do nothing
            }
        } catch (Exception e) {
            Slog.e(TAG, "channelRead exception " + e);
        } finally {
            m.release();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Slog.e(TAG, "exceptionCaught--" + cause);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                mReadIdleCount++;
                Slog.e(TAG, "read_idle channel=" + ctx.channel() + " mReadIdleCount=" + mReadIdleCount);
                if (mReadIdleCount > 1) {
                    //第二次超时了，关闭链接，稍后重连
                    ctx.channel().close();
                } else {
                    sendPingMessage(ctx.channel());
                }
            }
        }
    }

    /**
     * 发送ping消息
     *
     * @param ch       channel*
     */
    private void sendPingMessage(Channel ch) {
        ch.writeAndFlush(new byte[]{(byte)CloudMessage.TYPE_PING});
    }
}
